/*******************************************************************************
 * Copyright IBM Corp. and others 2000
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License 2.0 which accompanies this
 * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
 * or the Apache License, Version 2.0 which accompanies this distribution
 * and is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception [1] and GNU General Public
 * License, version 2 with the OpenJDK Assembly Exception [2].
 *
 * [1] https://www.gnu.org/software/classpath/license.html
 * [2] https://openjdk.org/legal/assembly-exception.html
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
 *******************************************************************************/

#include <stddef.h>
#include <stdint.h>
#include "env/StackMemoryRegion.hpp"
#include "compile/Compilation.hpp"
#include "control/Options.hpp"
#include "control/Options_inlines.hpp"
#include "env/TRMemory.hpp"
#include "il/Node.hpp"
#include "infra/Assert.hpp"
#include "infra/BitVector.hpp"
#include "optimizer/DataFlowAnalysis.hpp"

class TR_BlockStructure;
class TR_Structure;
namespace TR { class Optimizer; }

TR_DataFlowAnalysis::Kind TR_Liveness::getKind()
   {
   return Liveness;
   }

TR_Liveness *TR_Liveness::asLiveness()
   {
   return this;
   }

bool TR_Liveness::supportsGenAndKillSets()
   {
   return true;
   }

int32_t TR_Liveness::getNumberOfBits()
   {
   return _liveVariableInfo->numLocals();
   }

void TR_Liveness::analyzeNode(TR::Node *, vcount_t, TR_BlockStructure *, TR_BitVector *)
   {
   }

TR_Liveness::TR_Liveness(TR::Compilation           *comp,
                         TR::Optimizer           *optimizer,
			                TR_Structure               *rootStructure,
                         bool                        ignoreOSRUses,
                         TR_LiveVariableInformation *liveVariableInfo,
                         bool                        splitLongs,
                         bool                        includeParms)
   : TR_BackwardUnionBitVectorAnalysis(comp, comp->getFlowGraph(), optimizer, comp->getOption(TR_TraceLiveness)),
     _liveVariableInfo(liveVariableInfo)
   {
   _traceLiveness = comp->getOption(TR_TraceLiveness);

   if (liveVariableInfo == NULL)
      {
      // can be re-used by the caller because it's allocated in caller's stack
      _liveVariableInfo = new (trStackMemory()) TR_LiveVariableInformation(comp, optimizer, rootStructure, splitLongs, includeParms,
                                                                           ignoreOSRUses);
      _liveVariableInfo->collectLiveVariableInformation();
      }
   }

void TR_Liveness::perform(TR_Structure *rootStructure)
   {
   if (traceLiveness())
      traceMsg(comp(), "Starting Liveness analysis\n");

   if (_liveVariableInfo->numLocals() == 0)
      return; // Nothing to do if there are no locals

   if (comp()->getVisitCount() > 8000)
      comp()->resetVisitCounts(1);

   // Allocate the block info before setting the stack mark - it will be used by
   // the caller
   //
   initializeBlockInfo();

   {
   TR::StackMemoryRegion stackMemoryRegion(*trMemory());

   performAnalysis(rootStructure, false);

   if (traceLiveness())
      {
      for (int32_t i = 1; i < _numberOfNodes; ++i)
         {
         if (_blockAnalysisInfo[i])
            {
            traceMsg(comp(), "\nLive variables for block_%d: ",i);
            _blockAnalysisInfo[i]->print(comp());
            }
         }
      traceMsg(comp(), "\nEnding Liveness analysis\n");
      }
   } // scope of the stack memory region

   }

bool TR_Liveness::postInitializationProcessing()
   {
   if (traceLiveness())
      {
      for (int32_t i = 1; i < _numberOfNodes; ++i)
         {
         traceMsg(comp(), "\nGen and kill sets for block_%d: ",i);
         if (_regularGenSetInfo[i])
            {
            traceMsg(comp(), " gen set ");
            _regularGenSetInfo[i]->print(comp());
            }
         if (_regularKillSetInfo[i])
            {
            traceMsg(comp(), " kill set ");
            _regularKillSetInfo[i]->print(comp());
            }
         if (_exceptionGenSetInfo[i])
            {
            traceMsg(comp(), " exception gen set ");
            _exceptionGenSetInfo[i]->print(comp());
            }
         if (_exceptionKillSetInfo[i])
            {
            traceMsg(comp(), " exception kill set ");
            _exceptionKillSetInfo[i]->print(comp());
            }
         }
      }
   return true;
   }

void TR_Liveness::initializeGenAndKillSetInfo()
   {
   _liveVariableInfo->initializeGenAndKillSetInfo(_regularGenSetInfo, _regularKillSetInfo, _exceptionGenSetInfo, _exceptionKillSetInfo);
   }


void TR_Liveness::analyzeTreeTopsInBlockStructure(TR_BlockStructure *blockStructure)
   {
   TR_ASSERT(false, "Liveness should use gen and kill sets");
   }
